﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.WebPartPages;
using RoketSolutions.SP2010.Infrostructure.Localization;
using RoketSolutions.SP2010.Infrostructure.Localization.Providers.Interfaces;
using RoketSolutions.SP2010.Infrostructure.UI.WebParts.Interfaces;
using RoketSolutions.SP2010.Infrostructure.UI.WebParts.ToolParts;
using RoketSolutions.SP2010.Infrostructure.Common.Extensions;
using WebPart = Microsoft.SharePoint.WebPartPages.WebPart;


namespace RoketSolutions.SP2010.Infrostructure.UI.WebParts
{
    public abstract class LocalizableWebPart : WebPart, ILocalizableWebPart, IResourceConfigStorage
    {
        #region / Constructor /

        protected LocalizableWebPart()
        {
            ExportMode = WebPartExportMode.All;
            ChromeType = PartChromeType.None;
        }

        #endregion

        #region / Properties /

        ResourceConfig _config;
        LocalizationSettings _settings;
        private bool _needSetupSettings = true;

        public ResourceConfig ResourceConfig
        {
            get
            {
                if (_config == null)
                {
                    _config = new ResourceConfig();

                    if (IsWebPartAdded)
                    {
                        SetupConfig(_config);
                    }
                }
                return _config;
            }
            set { _config = value; }
        }

        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public LocalizationSettings LocalizationSettings
        {
            get
            {
                if (_settings == null)
                    _settings = new LocalizationSettings();

                if (IsWebPartAdded && _needSetupSettings)
                {
                    _needSetupSettings = false;
                    SetupSettings(_settings);
                }
                return _settings;
            }
            set
            {
                _settings = value;
                _needSetupSettings = true;
                ResourceConfig = null;
            }
        }

        WebPartManager _wpManager;
        protected WebPartManager WpManager
        {
            get { return _wpManager ?? (_wpManager = WebPartManager.GetCurrentWebPartManager(Page)); }
        }

        protected bool IsEditMode
        {
            get { return WpManager.DisplayMode == WebPartManager.EditDisplayMode; }
        }

        protected bool IsDesignMode
        {
            get { return WpManager.DisplayMode == WebPartManager.DesignDisplayMode; }
        }

        protected bool IsDisplayMode
        {
            get
            {
                return WpManager.DisplayMode == WebPartManager.BrowseDisplayMode;
            }
        }

        protected bool IsWebPartAdded
        {
            get { return Page != null; }
        }

        protected abstract string ResourcesFolderPath { get; }

        #endregion

        #region / Methods /

        public override ToolPart[] GetToolParts()
        {
            var tools = new List<ToolPart>();

            // if supported languages are specified then add localization tool part
            if (LocalizationSettings.SupportedLanguages.Any())
            {
                tools.Add(new LocalizationToolPart(LocalizationSettings));
            }

            // retrieve standard tool parts
            tools.AddRange(base.GetToolParts());

            return tools.ToArray();
        }

        public ResourceConfig GetConfig()
        {
            return ResourceConfig;
        }

        public string GetLocalizedString<TSource>(Expression<Func<TSource, object>> propertyKey)
        {
            return Resources.For<TSource>(GetConfig()).Get(propertyKey);
        }

        public void ApplySettings(LocalizationSettings settings)
        {
            LocalizationSettings = settings;
        }

        private void SetupSettings(LocalizationSettings settings)
        {
            // check whether the resources folder is specified
            if (!ResourcesFolderPath.IsNullOrEmpty())
            {
                var resourceFolder = new DirectoryInfo(ResourcesFolderPath);
                if (resourceFolder.Exists)
                {
                    // load available languages
                    foreach (var file in resourceFolder.GetFiles("*.xml"))
                    {
                        var filename = Path.GetFileNameWithoutExtension(file.Name);
                        var tokens = filename.Split('.');
                        var lang = tokens[tokens.Length - 1];

                        if (IsValidCulture(lang) && !settings.SupportedLanguages.Contains(lang, true))
                            settings.SupportedLanguages.Add(lang);
                    }
                }
            }

            // check whether the browser language should be detected
            if (settings.UseAutoDetectMode && settings.SupportedLanguages.Any() && Page.Request.UserLanguages != null)
            {
                var detectLang = string.Empty;
                var langs = new List<string>(Page.Request.UserLanguages) { "en-us" };
                foreach (var lang in langs)
                {
                    if (IsValidCulture(lang))
                    {
                        detectLang = lang;
                        break;
                    }
                }
                settings.AutoDetectLanuguage = detectLang;
            }
            else
            {
                settings.AutoDetectLanuguage = string.Empty;
            }
        }

        private void SetupConfig(ResourceConfig config)
        {
            config.ResourcesFolderPath = ResourcesFolderPath;

            if (LocalizationSettings.UseAutoDetectMode && !LocalizationSettings.AutoDetectLanuguage.IsNullOrEmpty())
            {
                config.CurrentCulture = CultureInfo.CreateSpecificCulture(LocalizationSettings.AutoDetectLanuguage);
            }
            else if (!LocalizationSettings.UseAutoDetectMode && !LocalizationSettings.SelectedLanuguage.IsNullOrEmpty())
            {
                config.CurrentCulture = CultureInfo.CreateSpecificCulture(LocalizationSettings.SelectedLanuguage);
            }
            else
            {
                config.CurrentCulture = null;
            }
        }

        private bool IsValidCulture(string lang)
        {
            try
            {
                var culture = CultureInfo.CreateSpecificCulture(lang);
                return !culture.IsNeutralCulture;
            }
            catch (Exception)
            {
                return false;
            }
        }

        #endregion

    }
}